// $codepro.audit.disable useEquals
/*
 * Records package
 */
package edu.gatech.oad.records;

import javax.swing.DefaultListModel;
import javax.swing.JComponent;
import javax.swing.JList;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JButton;
import javax.swing.JScrollPane;
import javax.swing.JLabel;
import javax.swing.BoxLayout;

import java.awt.BorderLayout;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.swing.border.TitledBorder;

import edu.gatech.oad.user.User;
/**
 * Panel used for creating and editing an invoice
 * @author Nathan Hurley
 * @version 1.0
 */
public class EditInvoicePanel extends JPanel {

	/**
	 * For serialization
	 */
	private static final long serialVersionUID = 1L;
	
	/**
	 * Invoice used in panel
	 */
	private final Invoice curInvoice;
	
	/**
	 * Buttons to add and view invoices
	 */
	private final JButton add, viewInvoice;
	
	/**
	 * Remove button
	 */
	private final JButton remove;
	
	/**
	 * Total cost of the Invoice
	 */
	private final JLabel total;
	
	/**
	 * Map for the known treatments and their cost
	 */
	private final Map<String, Double> treatments;
	
	/**
	 * Panels used to hold different components
	 */
	private final JPanel title, addedToBill, buttonsPanel, 
	editPanel, testPan2;
	
	/**
	 * Panel for the added treatments
	 */
	private final JPanel treatmentAddPanel;
	
	/**
	 * Strings used for the list 
	 */
	private final String[] availTreatments  = {"Vaccines", 
			"    Flu", "    Tetanus", "    " +
			"MMR", "    Hepatitis A", "    Steroid", "Labs", "   Urinalysis (BUN)", 
			"    Urinalysis (Drug Test)", "    CBC", "    Cholesterol", "    HIV", 
			"    Glucose", "    Adrenal", "    EKG", "    MRI", "Treatments", 
			"    Office Visit", "    Phone Consult", "    Physical", "Other"}; 
	
	/**
	 * Lists used to show available and added treatments
	 */
	private final JList available, added;
	
	/**
	 * List model
	 */
	private final DefaultListModel addedModel;
	
	/**
	 * Current user of the panel
	 */
	private final User curUser;
	
	/**
	 * Listener for the buttons
	 */
	private final ButtonListener curListen;
	
	/**
	 * Cost for flu shot and urinalysis
	 */
	private static final double FLU_URINE = 25.00;
	
	/**
	 * Cost of MMR
	 */
	private static final double MMR = 15.00;
	
	/**
	 * Cost of Tetanus shot
	 */
	private static final double TETANUS = 30.00;
	
	/**
	 * Cost of Hepatitis treatment
	 */
	private static final double HEPATITIS_URINE = 50.00;
	
	/**
	 * Cost of steroid
	 */
	private static final double STEROID = 56.00;
	
	/**
	 * General cost for a treatment
	 */
	private static final double GEN_COST = 75.00;
	
	/**
	 * Cost for cholesterol check
	 */
	private static final double CHOLEST = 40.00;
	
	/**
	 * Cost of HIV test and EKG
	 */
	private static final double HIV_EKG = 100.00;
	
	/**
	 * Cost for Adrenal check
	 */
	private static final double ADRENAL = 65.00;
	
	/**
	 * Cost for MRI
	 */
	private static final double MRI = 1000.00;
	
	/**
	 * Cost for phone consult
	 */
	private static final double PHONE = 35.00;
	
	/**
	 * Width of panel
	 */
	private static final int WIDTH = 500;
	
	/**
	 * Width for added and available treatments
	 */
	private static final int HALF_WIDTH = 250;
	
	/**
	 * Columns for the GridLayout
	 */
	private static final int COLS = 2;
	
	/**
	 * cell width
	 */
	private static final int CELL_WIDTH = 150;
	
	/**
	 * Logger used for exceptions
	 */
	private static final Logger LOGGER = Logger.getLogger(
			"edu.gatech.oad.records.EditInvoicePanel");
	
	/**
	 * Creates the panel
	 * @param curInvoice the invoice to build the panel around
	 * @param curUser the current user of the panel
	 */
	public EditInvoicePanel(Invoice curInvoice, User curUser){ // $codepro.audit.disable com.instantiations.assist.eclipse.analysis.audit.rule.effectivejava.constructorsOnlyInvokeFinalMethods
		this.curInvoice = curInvoice;
		this.curUser = curUser;
		/*Initialize components*/
		title = new JPanel();
		testPan2 = new JPanel();
		addedToBill = new JPanel();
		addedToBill.setPreferredSize(new Dimension(HALF_WIDTH, HALF_WIDTH));
		buttonsPanel = new JPanel(new BorderLayout());
		editPanel = new JPanel(new GridLayout(1, COLS));
		editPanel.setPreferredSize(new Dimension(HALF_WIDTH, WIDTH));
		treatmentAddPanel = new JPanel();
		treatmentAddPanel.setPreferredSize(new Dimension(HALF_WIDTH, HALF_WIDTH));
		curListen = new ButtonListener();
		add = new JButton("  >>  ");
		add.addActionListener(curListen);
		remove = new JButton("  <<  ");
		remove.addActionListener(curListen);
		viewInvoice = new JButton("View Current Invoice");
		viewInvoice.addActionListener(curListen);
		available = new JList(availTreatments);
		available.addMouseListener(new ListClickListener());
		addedModel = new DefaultListModel();
		added = new JList(addedModel);
		added.setFixedCellWidth(CELL_WIDTH);
		available.setFixedCellWidth(CELL_WIDTH);
		added.addMouseListener(new ListClickListener());
		treatments = new HashMap<String, Double>();
		total = new JLabel("Total: $" + curInvoice.getCost());
		/*Format and add components*/
		formatComponents();
		initializeTreatments();
		setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
		setPreferredSize(new Dimension(0, 0));
		addToPanels();
	}
	
	/**
	 * Formats the layout and different components
	 */
	public final void formatComponents(){
		title.setBorder(new TitledBorder("Creating an Invoice"));
		title.setLayout(new BoxLayout(title, BoxLayout.Y_AXIS));
		addedToBill.setBorder(new TitledBorder("Current Bill"));
		treatmentAddPanel.setBorder(new TitledBorder("Add to Invoice"));
		treatmentAddPanel.setLayout(new BoxLayout(treatmentAddPanel, BoxLayout.Y_AXIS));
		addedToBill.setLayout(new BoxLayout(addedToBill, BoxLayout.Y_AXIS));
		for(Cost c : curInvoice.getTreatmentsBilled()){//add invoices to list 
			addedModel.addElement(c.getDescription());
		}
		/*Align components*/
		title.setAlignmentX(RIGHT_ALIGNMENT);
	}
	
	/**
	 * Adds the components to the different panels
	 */
	public final void addToPanels(){
		add(title);
		add(editPanel);
		title.add(new JLabel("<html>Patient: " + 
			curInvoice.getAppointment().getPatient().getName() + "</html>"));
		title.add(new JLabel("<html>Appointment Date: " + curInvoice.getDate()));
		treatmentAddPanel.add(new JScrollPane(available));
		editPanel.add(treatmentAddPanel);
		editPanel.add(addedToBill);
		final JPanel testPan = new JPanel();
		testPan.add(remove);
		testPan.add(add);
		buttonsPanel.add(testPan, BorderLayout.NORTH);
		buttonsPanel.add(testPan2, BorderLayout.CENTER);
		addedToBill.add(new JScrollPane(added));
		add(buttonsPanel);
		testPan2.setLayout(new BoxLayout(testPan2, BoxLayout.Y_AXIS));
		total.setAlignmentX(CENTER_ALIGNMENT);
		viewInvoice.setAlignmentX(CENTER_ALIGNMENT);
		testPan2.add(total);
		testPan2.add(viewInvoice);
	}
	
	/**
	 * Wraps the given component in a container
	 * @param comp the component to wrap
	 * @return the wrapped component
	 */
	public static JComponent wrap(JComponent comp){
        final JPanel panel = new JPanel();
        panel.add(comp);
        return panel;
    }
	 
	/**
	 * Sets up the Map used for the different known treatments
	 */
	public final void initializeTreatments(){
		treatments.put("Flu", FLU_URINE);
		treatments.put("MMR", MMR);
		treatments.put("Tetanus", TETANUS);
		treatments.put("Hepatitis A", HEPATITIS_URINE);
		treatments.put("Steroid", STEROID);
		treatments.put("Urinalysis (BUN)", HEPATITIS_URINE);
		treatments.put("Urinalysis (Drug Test)", FLU_URINE);
		treatments.put("CBC", GEN_COST);
		treatments.put("Cholesterol", CHOLEST);
		treatments.put("HIV", HIV_EKG);
		treatments.put("Glucose", GEN_COST);
		treatments.put("Adrenal", ADRENAL);
		treatments.put("EKG", HIV_EKG);
		treatments.put("MRI", MRI);
		treatments.put("Office Visit", HEPATITIS_URINE);
		treatments.put("Phone Consult", PHONE);
		treatments.put("Physical", GEN_COST);
	}
	
	/**
	 * The Listener for the JButtons handles adding and removing from the lists
	 * @author Nathan Hurley
	 * @version 1.0
	 */
	private class ButtonListener implements ActionListener{
		/**
		 * Method executed when a button has been clicked
		 * @param e the event that has occurred
		 */
		public void actionPerformed(ActionEvent e){
			if(e.getSource() == add && available.getSelectedIndex() != -1){//adding to list
				if(canAdd()){
					addToAddedList();
				}
				else if(available.getSelectedValue() == "Other"){//other selected from list
					addOther();
				}
			}
			else if(e.getSource() == remove && added.getSelectedIndex() != -1){//remove from list
				removeFromAdded();
			}
			else if(e.getSource() == viewInvoice){//changes panel to viewing the invoice
				final Container curContainer = title.getParent();
				curContainer.removeAll();
				curContainer.add(new InvoicePanel(curInvoice, curUser));
				((JPanel) (curContainer)).updateUI();
				validate();
			}
		}
		
		/**
		 * @return String form of listener
		 */
		public String toString(){
			return "Button Listener for EditInvoicePanel";
		}
	}
	
	/**
	 * Listener for clicks on the JLists to add or remove from JLists
	 * @author Nathan Hurley
	 * @version 1.0
	 */
	private class ListClickListener extends MouseAdapter{
		/**
		 * Double click
		 */
		private static final int MAX_CLICKS = 2;
		
		/**
		 * Adds or removes from JList when user double clicks an element in one of the
		 * JLists
		 * @param evt the mouse event that has just occurred
		 */
		public void mouseClicked(MouseEvent evt) {
	        final JList list = (JList) evt.getSource();
	        if(list.equals(available)){
	        	if (evt.getClickCount() == MAX_CLICKS){
	        		if(canAdd()){
	        			addToAddedList();
	        		}
	        		else if(available.getSelectedValue().equals("Other")){
	        			addOther();
	        		}
	        	}
	        }
	        else if(list.equals(added)){
	        	if (evt.getClickCount() == MAX_CLICKS) {
	        		removeFromAdded();
	        	} 
	        }
	    }
		
		/**
		 * @return String form of listener
		 */
		public String toString(){
			return "List Listener for the EditInvoicePanel";
		}
	}
	
	/**
	 * Adds an element to the added treatments list
	 */
	public void addToAddedList(){
		addedModel.addElement(((String) available.getSelectedValue()).trim());
		curInvoice.setCost(treatments.get(((String) available.getSelectedValue()).trim())
				+ curInvoice.getCost());//set new cost
		curInvoice.addTreatment(new Cost(((String) available.getSelectedValue()).trim(), 
				treatments.get(((String) available.getSelectedValue()).trim())));
		total.setText("Total: $" + curInvoice.getCost());
	}
	
	/**
	 * @return true if item selected in list can be added to the
	 * Invoice
	 */
	public boolean canAdd(){
		return available.getSelectedValue() != "Vaccines" && 
		available.getSelectedValue() != "Labs" && 
		available.getSelectedValue() != "Treatments" && 
		available.getSelectedValue() != "Other";
	}
	
	/**
	 * If user adds "Other" treatment to the Invoice
	 */
	public void addOther(){
		final String descriptionResult = JOptionPane.showInputDialog(treatmentAddPanel, 
				"Please enter the name of this treatment:");//prompt user for name
		final String result = JOptionPane.showInputDialog(treatmentAddPanel, 
				"Please enter the cost of this treatment:");//prompt user for cost
		try{
			final double cost = Double.parseDouble(result);
			final Cost newCost = new Cost(descriptionResult, cost);
			addedModel.addElement(newCost.getDescription());
			curInvoice.addTreatment(newCost);
			curInvoice.setCost(curInvoice.getCost() + cost);
			total.setText("Total: $" + curInvoice.getCost());
		}
		catch(NumberFormatException n){
			JOptionPane.showMessageDialog(treatmentAddPanel,
				    "Invalid Cost. Please enter a number",
				    "Warning",
				    JOptionPane.WARNING_MESSAGE);
			LOGGER.log(Level.WARNING, "Incorrect Input for requested cost", n);
		}
	}
	
	/**
	 * Removes an element from the added list
	 */
	public void removeFromAdded(){
		Cost foundCost = null;
		for(Cost c : curInvoice.getTreatmentsBilled()){//find the cost in the added list
			if(c.getDescription().equals(added.getSelectedValue())){
				foundCost = c;
				break;
			}
		}
		if(foundCost != null){
			curInvoice.setCost(curInvoice.getCost() - foundCost.getCost());
		}
		curInvoice.removeTreatment(foundCost);
		addedModel.removeElement((String) added.getSelectedValue()); // $codepro.audit.disable com.instantiations.assist.eclipse.analysis.unusedReturnValue
		total.setText("Total: $" + curInvoice.getCost());
	}
	
	/** 
	 * @return the current Invoice
	 */
	public Invoice getInvoice(){
		return curInvoice;
	}
	
	/**
	 * Checks if two EditInvoicePanels are equal
	 * @param o the object to compare to
	 * @return true if have the same Invoice false otherwise
	 */
	public boolean equals(Object o){
		if(this == o){
			return true;
		}
		if(o instanceof EditInvoicePanel){
			final EditInvoicePanel e = (EditInvoicePanel) o;
			if(e.getInvoice().equals(this.getInvoice())){
				return true;
			}
		}
		return false;
	}
	
	/**
	 * @return the hash code for the Invoice
	 */
	public int hashCode(){
		return this.getInvoice().hashCode();
	}
	
	/**
	 * @return String representation of the Invoice
	 */
	public String toString(){
		return curInvoice.toString();
	}
	
}
